import { CacheService } from '@app/cache';
import { ConfigureService } from '@app/configure';
import { ChargeOrder } from '@app/db/entities/ChargeOrder';
import { Merchant } from '@app/db/entities/Merchant';
import { MerchantDailyIncome } from '@app/db/entities/MerchantDailyIncome';
import { User } from '@app/db/entities/User';
import { UserWalletLog } from '@app/db/entities/UserWalletLog';
import { Injectable } from '@nestjs/common';
import { InjectRepository } from '@nestjs/typeorm';
import { AliIotService } from 'apps/ali-iot/src/ali-iot.service';
import { DataSource, Repository } from 'typeorm';
import { PayService } from './pay/pay.service';
import { Platform } from '@app/db/entities/Platform';
import { PlatformDailyIncome } from '@app/db/entities/PlatformDailyIncome';
import { PrivateChargeService } from './private-charge/private-charge.service';
import { Device } from '@app/db/entities/Device';
import { ChargingStation } from '@app/db/entities/ChargingStation';
import { ChargingStationDailyIncome } from '@app/db/entities/ChargingStationDailyIncome';
import { ChargeCardOrderService } from './charge-card-order/charge-card-order.service';
import { UtilsService } from '@app/utils';

@Injectable()
export class ChargeOrderMsgService {
  private key:string
  private startChargeResKey:string
  private endChargeResKey:string
  private userChargingOrderKey:string
  private deviceIdPortToOrderIdReg:string //设备id和端口号对应的订单id

  
  constructor(
    private readonly pay:PayService,
    private readonly cache:CacheService,
    private readonly config:ConfigureService,
    private readonly utils:UtilsService,
    private readonly aliIot:AliIotService,
    @InjectRepository(ChargeOrder) protected repository:Repository<ChargeOrder>,
    @InjectRepository(User) protected user:Repository<User>,
    @InjectRepository(Device) protected device:Repository<Device>,
    protected dataSource: DataSource,
    private chargeCardOrder:ChargeCardOrderService,

    private readonly privateCharge:PrivateChargeService

  ) {
    this.key = config.get('deviceMsgListKeys.chargeInfo')
    this.startChargeResKey = config.get('startChargeResKey')
    this.endChargeResKey = config.get('endChargeResKey')
    this.userChargingOrderKey = config.get('userChargingOrderKey')
    this.deviceIdPortToOrderIdReg = config.get('deviceIdPortToOrderIdReg')
  }




  start() {
    this.processQueue()
  }

  async processQueue() {
    try {
      const messages = await this.cache.client.rpop(this.key, 10); // 新消息
      //const messages = []
      //messages.push('{"topic":"/a1TlOaf5rs9/000000001001031/user/alternating/update","msg":{"type":6,"id":"000000001001031","order":"0000000000901032","msgId":"00000000000000000000000000901032","port":1,"s":1,"chargeTime":305,"chargequantity":0.558,"maxPower":7043}}')
      //messages.push('{"topic":"/a1TlOaf5rs9/000000001001030/user/alternating/update","msg":{"type":6,"id":"000000001001030","order":"0000000000901032","msgId":"00000000000000000000000000901032","port":1,"s":1,"chargeTime":11600,"chargequantity":0.598,"maxPower":190}}')
      
      if(!messages || messages.length == 0) return

      this.pay.conf() //获取配置


      for(let i = 0; i < messages.length; i ++) {
        console.log(messages[i])
        const content = JSON.parse(messages[i])
        if(!content) return
  
        const msg = content.msg
        
        if(msg.type == 2) { //开始充电的结果
          if(msg.order.endsWith('P')) {//私人充电
            this.privateCharge.startCharge(msg)
          }else {
            this.startCharge(Number(msg.order), Number(msg.id), msg.port, msg.s, msg.errCode)
          }
        }else if(msg.type == 6 ) { //服务端主动停止
          if(msg.order.endsWith('P')) {//私人充电
            this.privateCharge.stopCharge(msg)
          }else {
            this.stopCharge(msg)
          }

        }else if(msg.type == 13) { //设备自动停止充电
          if(msg.order.endsWith('P')) {//私人充电
            this.privateCharge.endCharge(content.topic, msg)
          }else {
            this.endCharge(content.topic, msg)
          }
          
        }else if(msg.type == 15) { //刷卡充电
          this.chargeCardOrder.order(msg).then(r => {
            console.log('rrrrrrrrrrr', r)
          })
        }
      }
    } catch (error) {
      console.error(`Error processing queue: ${error}`);
    } finally {
      this.processQueue();
    }
  }

  async startCharge(orderId:number, deviceId, port:number, status:number, err:number) {
    const order = await this.repository.findOne({
      where : {id : orderId},
      select : ['status', 'userId', 'feeAmount', 'feeRewardAmount', 'payType', 'clientSource']
    })


    if(!order || order.status != 0) return

    let f = 'y'


    if(status == 0) { //失败
        f = 'n'
        if(order.payType == 2) { //预付费
          await this.refund(orderId, order, err)
        }else { //后付费，应该请求退费
          if(order.clientSource == 1) { //微信退款
            this.pay.payscoreServiceorderCancel(String(orderId), '充电失败退款')
          }else if(order.clientSource == 2){ //支付宝退款

          }

          this.repository.update({id : orderId}, {status : 3, errorCode : err})
        }
    }else { //成功
      this.repository.update({id : orderId}, {status : 1})

      //把端口状态改成充电中
      this.device.update({id : deviceId}, {
        portStatus : () => {
          return `JSON_SET(port_status, "$[${port - 1}]", 1)`
        }
      })
    }


    this.cache.set(this.startChargeResKey + orderId, f, 20)
    

    if(status == 1) {
      this.cache.client.sadd(this.userChargingOrderKey + order.userId, orderId)
      this.cache.set(this.deviceIdPortToOrderIdReg.replace(/\?/, deviceId).replace(/\?/, String(port)), orderId)
    }

  }


  //手动停止的
  async stopCharge(msg) {
    let f = 'y'

    const orderId = Number(msg.order)

    if(isNaN(orderId)) return


    const deviceId = Number(msg.id)

    if(msg.s == 0) { //失败
      f = 'n'
    }else { //成功
      this.settle(orderId, msg.chargeTime, msg.chargequantity, msg.maxPower, 12) //12就是手动停止

      this.cache.del(this.deviceIdPortToOrderIdReg.replace(/\?/, String(deviceId)).replace(/\?/, String(msg.port)))


      //把端口状态改成空闲
      //console.log('把端口状态改成空闲')
      this.device.update({id : deviceId}, {
        portStatus : () => {
          return `JSON_SET(port_status, "$[${msg.port - 1}]", 0)`
        }
      })

    }

    this.cache.set(this.endChargeResKey + orderId, f, 20)
  }

  //设备结束的
  async endCharge(topic:string, msg) {
    
    const topics = topic.split('/')
    
    const message:any = {type : 14, s : 1, port : msg.port}
    if('cardID' in msg) {
      message.cardID = msg.cardID
    }

    this.aliIot.pubToDevice(msg.id, topics[1], message)
    const deviceId = Number(msg.id)

    if(msg.cardID == undefined || msg.cardID == 0) { //卡充电的
      this.cache.del(this.deviceIdPortToOrderIdReg.replace(/\?/, String(deviceId)).replace(/\?/, String(msg.port)))
      this.settle(Number(msg.order), msg.chargeTime, msg.chargequantity, msg.maxPower, msg.y)
    }else {
      this.chargeCardOrder.settle(Number(msg.order), msg.chargeTime, msg.chargequantity, msg.maxPower, msg.y)
    }
    

    //把端口状态改成空闲
    //console.log('把端口状态改成空闲')
    this.device.update({id : deviceId}, {
      portStatus : () => {
        return `JSON_SET(port_status, "$[${msg.port - 1}]", 0)`
      }
    })

  }

  async refund(orderId:number, order:ChargeOrder, err) {
    if(isNaN(orderId)) return
    const time = Math.floor(Date.now() / 1000)
    const feeAmount = Number(order.feeAmount)
    const feeRewardAmount = Number(order.feeRewardAmount)

    const queryRunner = await this.dataSource.createQueryRunner()
    await queryRunner.connect();
    await queryRunner.startTransaction();

    try {
      let user = await queryRunner.manager.findOne<User>(User, {
          where : {id : order.userId},
          select : ['amount', 'rewardAmount'],
          lock : {
              mode : 'pessimistic_read'
          }
      })



      let walletLog:{[key in keyof UserWalletLog]? : UserWalletLog[key]} = {
          userId : order.userId,
          type : 3,
          relationId : orderId,
          createTime : time,
          beforeAmount : user.amount,
          beforeRewardAmount : user.rewardAmount,
          afterAmount : user.amount,
          afterRewardAmount : user.rewardAmount
      }

      if(feeAmount > 0) {
        walletLog.afterAmount = user.amount = (Number(user.amount) + feeAmount).toFixed(2)
      }

      if(feeRewardAmount > 0) {
        walletLog.afterRewardAmount = user.rewardAmount = (Number(user.rewardAmount) + feeRewardAmount).toFixed(2)
      }


      //更新用户余额
      const r1 = await queryRunner.manager.update<User>(User, { id : order.userId }, user)
      if(r1.affected < 1) {
          await queryRunner.rollbackTransaction();
          return -1
      }

      //加入钱包明细
      const { raw } = await queryRunner.manager.insert<UserWalletLog>(UserWalletLog, walletLog)
      if(!raw || raw.affectedRows < 1) {
          await queryRunner.rollbackTransaction();
          return -2
      }

      //更改订单状态
      const r2 = await queryRunner.manager.update<ChargeOrder>(ChargeOrder, { id : orderId }, {
        status : 3,
        errorCode : err
      })
      if(r2.affected < 1) {
          await queryRunner.rollbackTransaction();
          return -3
      }


      await queryRunner.commitTransaction()

      return 1

    } catch (error) {
      await queryRunner.rollbackTransaction();
    } finally {
      await queryRunner.release();
    }

    return -4
  }

  async settle(orderId:number, chargeTime:number, kwh:number, maxPower:number, reason:number) {
    if(isNaN(orderId)) return
    console.log('结算' + orderId)
    const order = await this.repository.findOne({
      where : {id : orderId},
      //select : ['status', 'unitPrice', 'unitService', 'userId']
    })

    if(!order || order.status != 1) return


    const currentDate = new Date();  
    const todayStartTime = Math.floor(currentDate.setHours(0, 0, 0, 0) / 1000);
  
    const time = Math.floor(currentDate.getTime() / 1000)


    //amount是总的收益
    const amount = Number(((Number(order.unitPrice) + Number(order.unitService)) * kwh).toFixed(2))
    let updateData:{[key in keyof ChargeOrder]? : ChargeOrder[key]} = {stopReason : reason, status : 2, endTime : Math.floor(Date.now() / 1000), consumeAmount : String(amount), consumeKwh : kwh, chargeData : {time : chargeTime, maxPower : maxPower}}

    let platformProfit = amount

    const queryRunner = await this.dataSource.createQueryRunner()
    await queryRunner.connect();
    await queryRunner.startTransaction();



    try {
      if(order.payType == 2) { //预付费
        const offsetAmount = Number((Number(order.chargeAmount) - Number(amount)).toFixed(2)) //看看剩余多少钱
        if(offsetAmount > 0) { //有钱剩
          //看看先退充值余额，还是赠送余额
          const feeAmount = Number(order.feeAmount)
          const feeRewardAmount = Number(order.feeRewardAmount)

          let _feeAmount = 0 //要退的
          let _feeRewardAmount = 0 //要退的
          if(offsetAmount <= feeRewardAmount) { //剩余的钱全部退到赠送的余额
            _feeRewardAmount = offsetAmount
          }else {
            _feeRewardAmount = feeRewardAmount
            _feeAmount = offsetAmount - feeRewardAmount
          }

          let user = await queryRunner.manager.findOne<User>(User, {
              where : {id : order.userId},
              select : ['amount', 'rewardAmount'],
              lock : {
                  mode : 'pessimistic_read'
              }
          })


          let walletLog:{[key in keyof UserWalletLog]? : UserWalletLog[key]} = {
              userId : order.userId,
              type : 3,
              relationId : orderId,
              createTime : time,
              beforeAmount : user.amount,
              beforeRewardAmount : user.rewardAmount,
          }

          if(_feeAmount > 0) {
            walletLog.afterAmount = user.amount = (Number(user.amount) + _feeAmount).toFixed(2)
            order.feeAmount = (feeAmount - _feeAmount).toFixed(2)
            walletLog.amount = String(_feeAmount)
          }else {
            walletLog.afterAmount = user.amount
          }


          if(_feeRewardAmount > 0) {
            walletLog.afterRewardAmount = user.rewardAmount = (Number(user.rewardAmount) + _feeRewardAmount).toFixed(2)
            order.feeRewardAmount = (feeRewardAmount - _feeRewardAmount).toFixed(2)

            walletLog.rewardAmount = String(_feeRewardAmount)
          }else {
            walletLog.afterRewardAmount = user.rewardAmount
          }
          

          //更新用户余额
          const r1 = await queryRunner.manager.update<User>(User, { id : order.userId }, user)
          if(r1.affected < 1) {
              await queryRunner.rollbackTransaction();
              return -2
          }

          

          //加入钱包明细
          const { raw } = await queryRunner.manager.insert<UserWalletLog>(UserWalletLog, walletLog)
          if(!raw || raw.affectedRows < 1) {
              await queryRunner.rollbackTransaction();
              return -4
          }
        }
      }

      //更新订单
      const r2 = await queryRunner.manager.update<ChargeOrder>(ChargeOrder, { id : orderId }, updateData)
      if(r2.affected < 1) {
          await queryRunner.rollbackTransaction();
          return -2
      }

      if(amount > 0) {
        let merchantProfit = 0
        if(order.merchantId > 0) {
          //这是运营商分到的钱
          merchantProfit = this.utils.round(amount * Number(order.profitRate) / 100, 2)//Number((amount * Number(order.profitRate) / 100).toFixed(2))
          if(merchantProfit > 0) {
            platformProfit = Number((amount - merchantProfit).toFixed(2))
          }
            

          let merchant = await queryRunner.manager.findOne<Merchant>(Merchant, {
              where : {id : order.merchantId},
              select : ['amount', 'totalChargeOrderCount', 'totalChargeAmount', 'totalChargeKwh', 'totalChargeTime'],
              lock : {
                  mode : 'pessimistic_read'
              }
          })

          const r3 = await queryRunner.manager.update<Merchant>(Merchant, { id : order.merchantId }, {
            amount : (Number(merchant.amount) + merchantProfit).toFixed(2),
            totalChargeAmount : (Number(merchant.totalChargeAmount) + merchantProfit).toFixed(2),
            totalChargeKwh : merchant.totalChargeKwh + kwh,
            totalChargeTime : merchant.totalChargeTime + chargeTime,
            totalChargeOrderCount : merchant.totalChargeOrderCount + 1
          })
          if(r3.affected < 1) {
              await queryRunner.rollbackTransaction();
              return -4
          }

          //加入商户每天收入记录
          const log = await queryRunner.manager.findOne<MerchantDailyIncome>(MerchantDailyIncome, {
            where : {merchantId : order.merchantId, date :todayStartTime},
            select : ['id', 'amount', 'kwh', 'time', 'chargeOrderCount']
          })
          if(log == null) {
            const { raw } = await queryRunner.manager.insert<MerchantDailyIncome>(MerchantDailyIncome, {
              merchantId : order.merchantId,
              date : todayStartTime,
              amount : String(merchantProfit),
              kwh : kwh,
              time : chargeTime,
              chargeOrderCount : 1
            })
            if(!raw || raw.affectedRows < 1) {
                await queryRunner.rollbackTransaction();
                return -4
            }
          }else {
            const r4 = await queryRunner.manager.update<MerchantDailyIncome>(MerchantDailyIncome, { id : log.id }, {
              amount : (Number(log.amount) + merchantProfit).toFixed(2),
              kwh : log.kwh + kwh,
              time : log.time + chargeTime,
              chargeOrderCount : log.chargeOrderCount + 1
            })
            if(r4.affected < 1) {
                await queryRunner.rollbackTransaction();
                return -4
            }
          }
        }

        //站点
        if(order.stationId > 0) {
          let station = await queryRunner.manager.findOne<ChargingStation>(ChargingStation, {
              where : {id : order.stationId},
              select : ['totalChargeAmount', 'totalChargeKwh', 'totalChargeOrderCount', 'totalChargeTime'],
              lock : {
                  mode : 'pessimistic_read'
              }
          })

          if(station != null) {
            const r3 = await queryRunner.manager.update<ChargingStation>(ChargingStation, { id : order.stationId }, {
              totalChargeAmount : (Number(station.totalChargeAmount) + merchantProfit).toFixed(2),
              totalChargeKwh : station.totalChargeKwh + kwh,
              totalChargeTime : station.totalChargeTime + chargeTime,
              totalChargeOrderCount : station.totalChargeOrderCount + 1
            })
            if(r3.affected < 1) {
                await queryRunner.rollbackTransaction();
                return -4
            }
  
            //加入站带你每天收入记录
            const log = await queryRunner.manager.findOne<ChargingStationDailyIncome>(ChargingStationDailyIncome, {
              where : {stationId : order.stationId, date :todayStartTime},
              select : ['id', 'amount', 'kwh', 'time', 'chargeOrderCount']
            })
            if(log == null) {
              const { raw } = await queryRunner.manager.insert<ChargingStationDailyIncome>(ChargingStationDailyIncome, {
                stationId : order.stationId,
                date : todayStartTime,
                amount : String(merchantProfit),
                kwh : kwh,
                time : chargeTime,
                chargeOrderCount : 1
              })
              if(!raw || raw.affectedRows < 1) {
                  await queryRunner.rollbackTransaction();
                  return -4
              }
            }else {
              const r4 = await queryRunner.manager.update<ChargingStationDailyIncome>(ChargingStationDailyIncome, { id : log.id }, {
                amount : (Number(log.amount) + merchantProfit).toFixed(2),
                kwh : log.kwh + kwh,
                time : log.time + chargeTime,
                chargeOrderCount : log.chargeOrderCount + 1
              })
              if(r4.affected < 1) {
                  await queryRunner.rollbackTransaction();
                  return -4
              }
            }
          }

          
        }


        //平台入账
        let platform = await queryRunner.manager.findOne<Platform>(Platform, {
            where : {id : 1},
            select : ['totalChargeOrderCount', 'totalAmount', 'totalProfit', 'totalKwh', 'totalTime', 'id'],
            lock : {
                mode : 'pessimistic_read'
            }
        })
        const r5 = await queryRunner.manager.update<Platform>(Platform, { id : platform.id }, {
          totalAmount : (Number(platform.totalAmount) + amount).toFixed(2),
          totalProfit : (Number(platform.totalProfit) + platformProfit).toFixed(2),
          totalKwh : platform.totalKwh + kwh,
          totalTime : platform.totalTime + chargeTime,
          totalChargeOrderCount : platform.totalChargeOrderCount + 1
        })
        if(r5.affected < 1) {
            await queryRunner.rollbackTransaction();
            return -5
        }

        //加入平台每天收入记录
        const log = await queryRunner.manager.findOne<PlatformDailyIncome>(PlatformDailyIncome, {
          where : {date :todayStartTime},
          select : ['id', 'amount', 'kwh', 'time', 'profit', 'chargeOrderCount']
        })
        if(log == null) {
          const { raw } = await queryRunner.manager.insert<PlatformDailyIncome>(PlatformDailyIncome, {
            date : todayStartTime,
            amount : String(amount),
            profit : String(platformProfit),
            kwh : kwh,
            time : chargeTime,
            chargeOrderCount : 1
          })
          if(!raw || raw.affectedRows < 1) {
              await queryRunner.rollbackTransaction();
              return -6
          }
        }else {
          const r6 = await queryRunner.manager.update<PlatformDailyIncome>(PlatformDailyIncome, { id : log.id }, {
            amount : (Number(log.amount) + amount).toFixed(2),
            profit : (Number(log.profit) + platformProfit).toFixed(2),
            kwh : log.kwh + kwh,
            time : log.time + chargeTime,
            chargeOrderCount : log.chargeOrderCount + 1
          })
          if(r6.affected < 1) {
              await queryRunner.rollbackTransaction();
              return -4
          }
        }

      }


      if(order.payType == 1) {
        this.pay.payscoreServiceorderComplete(String(orderId), amount)
      }
      
      await queryRunner.commitTransaction()


      console.log('结算完成')

    } catch (error) {
      console.log('----------')
      console.log(error)
      await queryRunner.rollbackTransaction();
    } finally {
      await queryRunner.release();
      //从充电中订单中移除
      this.cache.client.srem(this.userChargingOrderKey + order.userId, orderId)
    }

    

    


    //发送信息
    this.user.findOne({
      where : {id : order.userId},
      select : ['openid', 'source']
    }).then(user => {
      if(user) {
        this.pay.endNotify(user, {
          ...order,
          ...updateData
        })
      }
    })

  }
}
